﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Chisel.Core
{
	/// <summary>
	/// Arguments for a zoom event.
	/// </summary>
	public class ZoomEventArgs : EventArgs
	{
		public ZoomEventArgs(double newVal)
			: base()
		{
			Value = newVal;
		}

		public double Value { get; private set; }
	}

	/// <summary>
	/// Handler delegate for zoom events.
	/// </summary>
	public delegate void ZoomHandler(object sender, ZoomEventArgs args);

	/// <summary>
	/// A control that lets the user zoom in and out in the canvas.
	/// </summary>
	public partial class ZoomControl : UserControl
	{
		public ZoomControl()
		{
			InitializeComponent();

			Value = 1;
			Step = 0.25;
			MinValue = 0.25;
			MaxValue = 4;

			_slider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(OnSliderChanged);
			_inButton.Click += new RoutedEventHandler(OnZoomIn);
			_outButton.Click += new RoutedEventHandler(OnZoomOut);
			_originalButton.Click += new RoutedEventHandler(OnZoomOriginal);
			_valueBox.LostFocus += new RoutedEventHandler(OnValueBoxLostFocus);

			UpdateControls();
		}

		/// <summary>
		/// The current zoom level.
		/// </summary>
		public double Value { get; private set; }

		/// <summary>
		/// The minimum zoom value.
		/// </summary>
		public double MinValue { get; set; }

		/// <summary>
		/// The maximum zoom value.
		/// </summary>
		public double MaxValue { get; set; }

		/// <summary>
		/// The amount that the zoom changes when the in and out buttons are pressed.
		/// </summary>
		public double Step { get; set; }

		/// <summary>
		/// This gets raised whenever the zoom value changes on the control.
		/// </summary>
		public event ZoomHandler ValueChanged;

		/// <summary>
		/// Set this to true when you're updating the zoom level.
		/// </summary>
		private bool _internalUpdate = false;

		/// <summary>
		/// Updates the controls based on the current value.
		/// </summary>
		private void UpdateControls()
		{
			_internalUpdate = true;
			_slider.Value = Value;
			_valueBox.Text = String.Format("{0,3}%", Value * 100);
			_internalUpdate = false;
		}

		/// <summary>
		/// Raises the ValueChanged event and updates the controls accordingly.
		/// </summary>
		private void RaiseChanged(double value)
		{
			Value = Math.Min(Math.Max(MinValue, value), MaxValue);
			if (ValueChanged != null)
				ValueChanged(this, new ZoomEventArgs(value));

			UpdateControls();
		}

		/// <summary>
		/// Handles the slider value changing.
		/// </summary>
		private void OnSliderChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
		{
			if (!_internalUpdate)
				RaiseChanged(_slider.Value);
		}

		/// <summary>
		/// Handles the zoom in button being clicked.
		/// </summary>
		private void OnZoomIn(object sender, RoutedEventArgs e)
		{
			RaiseChanged(Value + Step);
		}

		/// <summary>
		/// Handles the zoom out button being clicked.
		/// </summary>
		private void OnZoomOut(object sender, RoutedEventArgs e)
		{
			RaiseChanged(Value - Step);
		}

		/// <summary>
		/// Handles the original zoom button being clicked.
		/// </summary>
		private void OnZoomOriginal(object sender, RoutedEventArgs e)
		{
			RaiseChanged(1.0);
		}

		private void OnValueBoxLostFocus(object sender, RoutedEventArgs e)
		{
			if (!_internalUpdate)
			{
				try
				{
					double val = Double.Parse(_valueBox.Text);
					RaiseChanged(val / 100);
				}
				catch (Exception)
				{
					UpdateControls();
				}
			}
		}

	}
}
